home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EuroCD 3
/
EuroCD 3.iso
/
Programming
/
vbcc
/
doc
/
vbccm68k.doc
< prev
next >
Wrap
Text File
|
1998-06-24
|
13KB
|
299 lines
vbcc - C compiler (c) in 1995-97 by Volker Barthelmann
INTRODUCTION
vbcc is a free portable and retargetable ANSI C compiler.
It is clearly split into a target independant and a target dependant
part and supports emulating datatypes of the target machine on any
other machine so that it is possible to e.g. make a crosscompiler for
a 64bit machine on a 32bit machine.
This document only deals with the target dependant parts of the
Amiga68k version.
LEGAL
vbcc is (c) in 1995-96 by Volker Barthelmann. All code is written by me
and may be freely redistributed as long as no modifications are made
and nothing is charged for it.
Non-commercial usage of vbcc is allowed without any restrictions.
Commercial usage needs my written consent.
Sending me money, gifts, postcards etc. would of course be very nice
and may encourage further development of vbcc, but is not legally or
morally necessary to use vbcc.
ADDITIONAL OPTIONS FOR THIS VERSION
-cpu=n Generate code for cpu n (e.g. -cpu=68020), default: 68000
-fpu=n Generate code for fpu n (e.g. -fpu=68881), default: 0
-sd Use small data model (see below).
-sc Use small code model (see below).
-prof Insert code for profiling (not really usable yet).
-g Generate debugging hunks which contain addresses of static
objects and links assembly instructions to source lines.
This does not work with -gas.
-const-in-data
By default constant data will be placed in the code
section (and therefore is accessable with faster pc-relative
addressing modes). Using this option it will be placed in the
data section.
This could e.g. be useful if you want to use small data and
small code, but your code gets too big with all the constant
data.
Note that on operating systems with memory protection this
option will disable write-protection of constant data.
-use-framepointer
By default automatic variables are addressed through a7
instead of a5. This generates slightly better code, because
the function entry and exit overhead is reduced and a5 can be
used as register variable etc.
However this may be a bit confusing when debugging and you
can force vbcc to use a5 as a fixed framepointer.
-no-addressing-modes
The intermediate code does not contain any of the 68k
addressing modes, so if they are to be used an extra pass
over the intermediate code is necessary to recognize certain
patterns that can be expressed using a 68k addressing mode.
By default vbcc tries to use some 68k addressing modes.
Currently (ax)+ and subsets of (displ,ax,dy*skal) are used.
However not all cases where those addressing modes could be
used are recognized.
With this option you can prevent vbcc from searching for
possible addressing modes. This may simplify debugging.
-no-delayed-popping
By default arguments of function calls are not always popped
from the stack immediately after the call, so that the
arguments of several calls may be popped at once.
With this option vbcc can be forced to pop them after every
function call.
This may simplify debugging and very slightly reduce the
stack size needed by the compiled program.
-gas Create output suitable for the GNU assembler. This is
mainly useful to create code for other operating systems.
-no-fp-return
Do not return floats and doubles in floating-point registers
even if code for an fpu is generated. This is mainly useful
to create code for other operating systems.
-no-mreg-return
Do not use multiple registers to return types that do not
fit into a single register. This is mainly for backwards
compatibility.
-d2scratch obsolete
-noa4 obsolete
SOME INTERNALS
The current version generates assembler output for use with the PhxAss
assembler (c) by Frank Wille. Most peephole optimizations are done by the
assembler so vbcc only does some that the assembler cannot make.
The generated executables will probably only work with OS2.0 or higher.
With -gas assembler output suitable for the GNU assembler is generated
(the version must understand the Motorola syntax - some old ones do not).
The output is only slightly modified from the PhxAss-output and will
therefore result in worse code on gas. However this code generator should
be usable on most operating systems on 68k machines that way.
The register names are:
a0, a1, a2, a3, a4, a5, a6, a7
d0, d1, d2, d3, d4, d5, d6, d7
fp0, fp1, fp2, fp3, fp4, fp5, fp6, fp7
The registers d0, d1, a0, a1, fp0 and fp1 are used as scratch registers
(i.e. they can be destroyed in function calls), all other registers are
preserved.
All elementary types up to 4 bytes are returned in register d0 like
common on the Amiga (although I think pointers should better be returned
in a0). If compiled for an fpu, floating point values are returned in
fp0 unless -no-fpreturn is specified.
Types which are 8, 12 or 16 bytes large will be returned in several
registers (d0/d1/a0/a1) unless -no-mreg-return is specified.
All other types are returned by passing the function the address
of the result as a hidden argument - so when you call such a function
without a proper declaration in scope you can expect a crash.
You must not link objects together that have been compiled with
different settings!
vbcc uses d0-d7 and a0-a6 for temporary results and register variables
(a4 is used as small data pointer if -sd is used). a5 can be
used as frame pointer for automatic variables (but this is not necessary -
they can be accessed through a7, too). At the moment all local
variables are addressed via (dist,ax), so a function may have only ~32k
of local variables if code for <=68000 is generated.
The elementary data types are represented like:
type size in bits alignment in bytes
char 8 1
short 16 2
int 32 2
long 32 2
all pointers 32 2
float(fpu) 32 2 see below
double(fpu) 64 2 see below
Although it would be better to have all 32bit+ types aligned to 4 bytes
I chose 2 bytes to be compatible with the Amiga system structures which
unfortunately have longwords aligned to 4n+2-addresses.
The amiga68k code generator at the moment only works on systems
that store floats and doubles in a similar way (IEEE) like the Amiga.
SMALL DATA
vbcc can access static data in two ways. By default all such data will
be accessed with full 32bit addresses (large data model).
However there is a second way. You can set up an address register (a4)
to point into your data segment and then address data with a 16bit
offset through this register.
The advantages of the small data model are that your program will
usually be smaller (because the 16bit offsets use less space and no
relocation information is needed) and faster.
The disadvantages are that one address register cannot be used by the
compiler and that you can use it only if all your static data occupies
less than 64kb. Also you may not mix object modules and libraries that
have been compiled with different data models (you can call functions
compiled with large data model from object files compiled with small
data model, but not vice versa and only functions can be called that
way - other data cannot be accessed) and you probably have to use
PhxLnk then.
If you use small data together with functions which are called from
functions which have not been compiled with vbcc or with the small data
model then you _must_ call geta4() as the first statement in your
function (do not use automatic initializations prior to the call to
geta4).
Note that you must not call geta4() through a function pointer!
SMALL CODE
If you use the small code model calls to external functions (i.e. from
libraries or other object files) are done with 16bit offsets over
the program counter rather than with absolute 32bit addresses.
The advantage is slightly smaller and faster code.
The disadvantages are that all the code (including library functions)
must be small enough and that you may have to use PhxLnk. However
you can link objects/libraries together if they have been compiled
with different code models.
CPUs
At the moment the values of -cpu=n have those effects:
n>=68020: - 32bit multiplication/division/modulo is done with the
mul?.l, div?.l and div?l.l instructions
- tst.l ax is used
- extb.l dx is used
- 16/32bit offsets are used in certain addressing modes
- link.l is used
- addressing modes with scaling are used
- (dx) is used if no address register is available (not yet)
n==68040 - 8bit constants are not copied in data registers
FPUs
At the moment the values of -fpu=n have those effects:
n>68000: - floating point calculations are done using the fpu
n=68040:
n=68060: - instructions that have to be emulated on these fpus
will not be used; at the moment this only includes
the fintrz instruction in case of the 040
MATH
Integer math hopefully works without problems on all cpus. Long multiply
on cpus <68020 uses inline routines. This may increase code size a bit,
but it should be significantly faster, because function call overhead
is not necessary and the compiler can use the registers which already
contain the sources and/or need the result. However if anyone really
wants an option for using library routines for multiply, this can easily
be implemented. Long division and modulo is handled by calls to library
functions. At the moment standard library calls with parameter passing
via stack are used. This is rather slow, but division takes quite some
time anyway.
(mult/div/mod with constant powers of two are replaced by corresponding
bitwise operations (mod only if the other operand is unsigned), but
sums of powers of two not yet).
If no FPU is specified floating point math is done using the C=
math libraries. 32 bit IEEE format is used for float and 64 bit IEEE
for double.
Floating point math is done with the FPU if one is specified (see above).
Floating point values are kept in registers then and therefore may
have extended precision sometimes, which is not ANSI compliant (but
will usually cause no harm). When floating point values are stored in
memory they use the same IEEE formats as without FPU.
Float or double return values are passed in fp0.
Note that you must not link object files together if they were not
compiled with the same -fpu settings and that you have to link with
the proper math library (see vclib.doc).
STDARG
A possible <stdarg,h> could look like this:
typedef unsigned char *va_list;
#define va_start(ap, lastarg) ((ap) = (va_list)(&lastarg + 1))
#define va_arg(ap, type) ((ap) += \
(sizeof(type)<sizeof(int)?sizeof(int):sizeof(type)), ((type *)(ap))[-1])
#define va_end(ap) ((ap) = 0L)
KNOWN PROBLEMS
- Converting floating point values to unsigned integers is not correct
if the value is >LONG_MAX and code for an FPU is generated.
- The extended precision of the FPU registers can cause problems if
a program depends on the exact precision. Most programs will not
have trouble with that, but programs which do exact comparisons
with floating point types (e.g. to try to calculate the number
of significant bits) may not work as expected (especially if the
optimizer was turned on).
Volker Barthelmann volker@vb.franken.de
Kennedy-Ring 39
91301 Forchheim
Germany